/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package main;

import com.sun.net.httpserver.HttpServer;
import helper.Utilities;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;

/**
 *
 * @author Hallucinogen
 */
public class Tracker {

    public Tracker() {
        m_ManagedFile = new ConcurrentHashMap<String, CopyOnWriteArrayList<Peer> >();
    }

    
    public void onPeerDisconnected(Peer peer){
        Iterator it = m_ManagedFile.entrySet().iterator();

        while (it.hasNext()) {
            Map.Entry data = (Map.Entry)it.next();

            ((ArrayList<Peer>)data.getValue()).remove(peer);
        }
    }

    public void onPeerRequestFile(String fileName, Peer peer) {
        CopyOnWriteArrayList<Peer> value = m_ManagedFile.get(fileName);
        
        if (value == null) {
            value = new CopyOnWriteArrayList<Peer>();
            m_ManagedFile.put(fileName, value);
        }

        /** check peer existence */
        for (Peer val : value) {
            if (val.getAddress().equals(peer.getAddress())) {
                value.remove(val);
                
                break;
            }
        }
        peer.setLastRequest(System.currentTimeMillis());
        value.add(peer);
    }

    public ArrayList<Peer> getPeers(String fileName) {
        ArrayList<Peer> peers = new ArrayList<Peer>();
        CopyOnWriteArrayList<Peer> currentPeers = m_ManagedFile.get(fileName);

        for (Peer peer : currentPeers) {
            if (peer != null)
            peers.add(peer);
        }
        
        return peers;
    }

    public ArrayList<Peer> getPeers(String fileName, Peer requestingPeer) {
        ArrayList<Peer> peers = new ArrayList<Peer>();
        CopyOnWriteArrayList<Peer> currentPeers = m_ManagedFile.get(fileName);

        if (currentPeers == null) return null;

        for (Peer peer : currentPeers) {
            if (peer.getAddress().equals(requestingPeer.getAddress())) continue;

            peers.add(peer);
        }
        
        return peers;
    }

    public static void main(String[] args) throws IOException {
        InetSocketAddress socket = new InetSocketAddress(Utilities.TRACKER_PORT);
        HttpServer server = HttpServer.create(socket, 0);

        Tracker tracker = new Tracker();

        server.createContext("/", new TrackerHandler(tracker));
        server.setExecutor(Executors.newCachedThreadPool());
        server.start();

        System.out.println("Listening to port " + Utilities.TRACKER_PORT);

        while (true) {
            Iterator it = tracker.m_ManagedFile.entrySet().iterator();
            
            while (it.hasNext()) {
                Map.Entry data = (Map.Entry)it.next();

                CopyOnWriteArrayList<Peer> peers = (CopyOnWriteArrayList<Peer>)data.getValue();
                ArrayList<Peer> deleted = new ArrayList<Peer>();

                for (Peer peer : peers){
                    if (peer != null && System.currentTimeMillis() - peer.getLastRequest() > Utilities.INTERVAL) {
                        deleted.add(peer);
                    }
                }

                for (Peer peer : deleted){
                    peers.remove(peer);
                }
            }

            tracker.logFile();
        }
    }

    public void logFile() {
        Iterator it = m_ManagedFile.entrySet().iterator();

        while (it.hasNext()) {
            Map.Entry data = (Map.Entry)it.next();

            System.out.println("[" + (String)data.getKey() + "]");

            CopyOnWriteArrayList<Peer> peers = (CopyOnWriteArrayList<Peer>)data.getValue();

            for (Peer peer : peers){
                if (peer != null) {
                    System.out.println("\t" + peer.getAddress().toString());
                }
            }
        }
    }

    public ConcurrentHashMap<String, CopyOnWriteArrayList<Peer>> getManage(){
        return this.m_ManagedFile;
    }

    //private ArrayList<Peer> m_ConnectedPeer;
    private ConcurrentHashMap<String, CopyOnWriteArrayList<Peer> > m_ManagedFile;
}
